home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-11-22 | 9.7 KB | 367 lines | [TEXT/MPCC] |
- /*
- ** CTCPAsyncCall.cp
- **
- ** TurboTCP support library
- ** TCP asynchronous call class
- **
- ** Copyright © 1993-94, FrostByte Design / Eric Scouten
- **
- */
-
-
- #include "CTCPAsyncCall.h"
-
- #include "Global.h"
- #include "TCL.h"
-
- #include "CTCPDriver.h"
- #include "CTCPStream.h"
-
- #ifndef __MACTCP__ // for compatibility with old Univ Headers
- #define TCPIOCompletionUPP TCPIOCompletionProcPtr
- #endif
-
-
- // —— UPP for completion procedure (corrects a bug in <TCPPB.h>) ——
-
- #if GENERATINGCFM
-
- enum {
- TTCP_uppTCPIOCompletionProcInfo = kRegisterBased // •• was kCStackBased in <TCPPB.h>
- | REGISTER_ROUTINE_PARAMETER(1, kRegisterA0, SIZE_CODE(sizeof(struct TCPiopb*)))
- };
-
- UniversalProcPtr CTCPAsyncCall::completionProcUPP = NULL;
-
- #endif
-
-
- TCL_DEFINE_CLASS_M0(CTCPAsyncCall);
-
-
- // —— initiate, process TCP call ——
-
- /*______________________________________________________________________
- **
- ** DoAsyncCall (private methods)
- **
- ** Fills in the standard parameters for a TCP Device Manager call and executes the call.
- **
- ** theCsCode (short): TCP operation code
- ** theParamBlockPtr (TCPiopb*): parameter block for TCP call
- **
- ** return (OSErr): result code
- **
- */
-
- OSErr CTCPAsyncCall::DoAsyncCall(short theCsCode, TCPiopb* theParamBlockPtr)
-
- {
- BlockMove(theParamBlockPtr, &itsiopb.itsParamBlock, sizeof (TCPiopb));
- return DoAsyncCall(theCsCode);
- }
-
- OSErr CTCPAsyncCall::DoAsyncCall(short theCsCode) // version for use by DispatchNoCopyRcv
-
- {
- #if GENERATINGCFM // seems to be buggy here…
- itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) completionProcUPP;
- #else
- itsiopb.itsParamBlock.ioCompletion = (TCPIOCompletionUPP) CompletionProc;
- #endif
- itsiopb.itsParamBlock.ioCRefNum = (CTCPDriver::gTCPDriver)->GetTCPRefNum();
- itsiopb.itsParamBlock.csCode = theCsCode;
- itsiopb.itsQueue = &((CTCPDriver::gTCPDriver)->asyncQueue);
- PBControlAsync((ParmBlkPtr) &itsiopb.itsParamBlock);
- return itsiopb.itsParamBlock.ioResult;
- }
-
-
- /*______________________________________________________________________
- **
- ** ProcessCompletion (private method)
- **
- ** Respond to completion of this TCP call and all calls following it in the completion loop.
- ** After running through this loop, disposes of the call object, UNLESS it was a successful
- ** auto-receive call.
- **
- */
-
- void CTCPAsyncCall::ProcessCompletion()
-
- {
- Boolean disposeWhenDone;
-
-
- // dispatch to general completion routine or to optimized routine for no-copy-receive calls
-
- TRY {
- if (itsiopb.itsParamBlock.csCode == TCPNoCopyRcv)
- disposeWhenDone = DispatchNoCopyRcv();
- else
- disposeWhenDone = Dispatch();
- if (disposeWhenDone) {
- itsStream.ProcessAsyncCompletion(this);
- delete this;
- }
- } CATCH {
- itsStream.ProcessAsyncCompletion(this);
- delete this;
- } ENDTRY;
-
- }
-
-
- /*______________________________________________________________________
- **
- ** Dispatch (private method)
- **
- ** Called by ProcessCompletion to report back to the CTCPStream object. Does not dispose
- ** of object. Also, does not handle TCPNoCopyRcv commands (see DispatchNoCopyRcv
- ** method below).
- **
- ** return (Boolean): TRUE to dispose of call object when done
- **
- */
-
- Boolean CTCPAsyncCall::Dispatch()
-
- {
- rdsEntry* RDSPtr;
- wdsEntry* WDSPtr;
-
- if (itsiopb.itsParamBlock.ioResult) {
-
- // command failed, what was it?
-
- switch (itsiopb.itsParamBlock.csCode) {
-
- case TCPPassiveOpen:
- case TCPActiveOpen:
- itsStream.HandleOpenFailed(itsiopb.itsParamBlock.ioResult);
- break;
-
- case TCPSend:
- itsStream.HandleSendFailed((wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr,
- itsiopb.itsParamBlock.csParam.open.security,
- itsiopb.itsParamBlock.csParam.open.timeToLive, itsiopb.itsParamBlock.ioResult);
- break;
-
- case TCPRcv:
- if (itsiopb.itsParamBlock.ioResult == connectionClosing)
- break;
-
- case TCPClose:
- if (itsiopb.itsParamBlock.ioResult == connectionDoesntExist)
- break;
-
- case TCPRcvBfrReturn:
- if (itsiopb.itsParamBlock.ioResult == invalidRDS)
- break;
-
- default:
- itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
- break;
-
- }
- }
- else {
-
- // no error, dispatch success — what type of call was this anyway?
-
- switch (itsiopb.itsParamBlock.csCode) {
-
- case TCPPassiveOpen:
- case TCPActiveOpen:
- itsStream.HandleOpened();
- itsStream.StartAutoReceive();
- break;
-
- case TCPSend:
- WDSPtr = (wdsEntry*) itsiopb.itsParamBlock.csParam.send.wdsPtr;
- itsStream.HandleDataSent(WDSPtr, itsiopb.itsParamBlock.csParam.open.security,
- itsiopb.itsParamBlock.csParam.open.timeToLive);
- break;
-
- case TCPRcv:
- if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
- itsStream.RcvUrgentBegin();
- if (itsiopb.itsParamBlock.csParam.receive.markFlag)
- itsStream.RcvUrgentMark();
- itsStream.HandleDataArrived(itsiopb.itsParamBlock.csParam.receive.rcvBuff,
- itsiopb.itsParamBlock.csParam.receive.rcvBuffLen,
- itsStream.RcvUrgentStatus());
- break;
-
- case TCPClose:
- itsStream.HandleClosed();
- break;
-
- case TCPRcvBfrReturn:
-
- // if auto-receiving, re-issue the TCPNoCopyRcv command with same paramters
-
- if ((itsiopb.itsParamBlock.csParam.open.options[36]) && (itsStream.hasSessionOpen)) {
- itsiopb.itsParamBlock.csParam.receive.rdsLength = itsiopb.itsParamBlock.csParam.open.options[36];
- DoAsyncCall(TCPNoCopyRcv);
- return FALSE; // make sure call object stays around
- }
- else
- ForgetPtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
- break;
-
- } // switch
- } // if…else
-
- return TRUE; // always dispose of call object when done
-
- }
-
-
- /*______________________________________________________________________
- **
- ** DispatchNoCopyRcv (private method)
- **
- ** Optimized routine to handle completion of TCPNoCopyRcv calls.
- **
- ** return (Boolean): TRUE to dispose of call object when done
- **
- */
-
- Boolean CTCPAsyncCall::DispatchNoCopyRcv()
-
- {
- rdsEntry* RDSPtr;
-
-
- // respond to error condition
-
- if (itsiopb.itsParamBlock.ioResult) {
- if ((itsiopb.itsParamBlock.ioResult != connectionClosing)
- && (itsiopb.itsParamBlock.ioResult != connectionDoesntExist))
- itsStream.HandleTCPError(itsiopb.itsParamBlock.ioResult, itsiopb.itsParamBlock.csCode);
- ForgetPtr(itsiopb.itsParamBlock.csParam.receive.rdsPtr);
- return TRUE; // always dispose when call fails
- }
-
-
- // update urgent flags
-
- if (itsiopb.itsParamBlock.csParam.receive.urgentFlag)
- itsStream.RcvUrgentBegin();
- if (itsiopb.itsParamBlock.csParam.receive.markFlag)
- itsStream.RcvUrgentMark();
-
-
- // run through RDS and process each block of data
-
- RDSPtr = (rdsEntry*) itsiopb.itsParamBlock.csParam.receive.rdsPtr;
-
- while ((*RDSPtr).length) {
- itsStream.HandleDataArrived((*RDSPtr).ptr, (*RDSPtr).length, itsStream.rcvUrgent);
- RDSPtr++;
- }
-
-
- // return the buffers to MacTCP
-
- DoAsyncCall(TCPRcvBfrReturn);
-
-
- // if auto-receiving, the call will be reissued when the BfrReturn call is completed
-
- return FALSE; // keep call object around
-
- }
-
-
- /*______________________________________________________________________
- **
- ** GetCompletionProc (private static method)
- **
- ** If running on a PowerPC, get the completion procedure resource and build a routine
- ** descriptor. Since the completion proc is called frequently from the Device Driver and
- ** MacTCP (which are emulated 68K code), we provide a 68K completion proc to avoid
- ** the overhead of the mode switch. Therefore, this routine builds a fat routine descriptor
- ** containing the 68K and PPC versions. (The 68K version is found in the code resource
- ** 'Ttcp' 23000. It is the 68K equivalent of the completion procedure below.)
- **
- ** This routine does nothing in 68K builds (note the #ifdef/#endif that bracket the
- ** routine).
- **
- */
-
- void CTCPAsyncCall::GetCompletionProc()
-
- {
- #ifdef TCL_POWER_PC
-
- Handle codeHandle;
- Ptr codeEntry;
-
- codeHandle = GetResource('Ttcp', 23000);
- FailNIL(codeHandle);
- DetachResource(codeHandle);
- codeEntry = *codeHandle;
-
- completionProcUPP = NewFatRoutineDescriptor((ProcPtr) codeEntry, (ProcPtr) &CompletionProc,
- TTCP_uppTCPIOCompletionProcInfo);
- FailNIL(completionProcUPP);
-
- #endif
- }
-
-
- // —— completion procedure ——
-
- /*______________________________________________________________________
- **
- ** CompletionProc (private static method)
- **
- ** The asynchronous completion routine. Recieves notification that any asynchronous
- ** TCP I/O operation has been completed. This routine is used for all TCP calls placed by
- ** CTCPAsyncCall::DoAsyncCall.
- **
- ** Send notification to the TCP driver object that this call has been completed. The driver
- ** then queues the call for processing at the next event loop.
- **
- ** The struct TurboTCPiopb includes a pointer to the CTCPDriver queue so that we don’t
- ** need to access application globals in this loop. This improves performance, and
- ** also permits us to use a 68K code resource in an otherwise PowerPC environment
- ** to avoid the performance hit of mode switches.
- **
- ** INTERRUPT-LEVEL ROUTINE: Cannot make memory allocations, cannot make
- ** synchronous TCP calls, and cannot use the profiler.
- **
- ** iopb (struct TCPiobp*): the TCP I/O parameter block
- **
- */
-
- #ifndef TCL_POWER_PC
-
- #ifdef __MWERKS__
- #pragma profile off
- #pragma a6frames off
- #endif
-
- struct TurboTCPiopb* GetTheCall();
- #pragma parameter __A0 GetTheCall()
- extern struct TurboTCPiopb* GetTheCall() = 0x2048; // MOVEA.L A0,A0
- // Silly way of working around lack of #pragma parameter for member functions.
-
- pascal void CTCPAsyncCall::CompletionProc()
- {
- struct TurboTCPiopb* iopb = GetTheCall();
- Enqueue((QElemPtr) &(iopb->itsQElem), iopb->itsQueue);
- // CTCPDriver::ProcessNetEvents will pick this up later
- }
-
- #else // #ifndef TCL_POWER_PC
-
- pascal void CTCPAsyncCall::CompletionProc(struct TurboTCPiopb* iopb)
- {
- Enqueue((QElemPtr) &(iopb->itsQElem), iopb->itsQueue);
- // CTCPDriver::ProcessNetEvents will pick this up later
- }
-
- #endif // #ifndef TCL_POWER_PC